package com.smarttest.common.util.protocol.ems;

import static com.smarttest.common.util.protocol.ByteUtil.bcd2Date;
import static com.smarttest.common.util.protocol.ByteUtil.getFormatedVal;
import static com.smarttest.common.util.protocol.ByteUtil.parseByte2IntSign;
import static com.smarttest.common.util.protocol.ByteUtil.parseCanByte2Int;
import static com.smarttest.common.util.protocol.ByteUtil.parseCanDWord;
import static com.smarttest.common.util.protocol.ByteUtil.parseCanWord;
import static com.smarttest.common.util.protocol.ByteUtil.parseDWord2LongSign;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.smarttest.common.beans.protolcol.Index;
import com.smarttest.common.beans.protolcol.SmartMessage;
import com.smarttest.common.beans.protolcol.can.CanDetail;
import com.smarttest.common.beans.protolcol.can.CanDetailDongFeng;
import com.smarttest.common.beans.protolcol.can.CanDistance;


public class EmsParser {
	
	private Logger log = LoggerFactory.getLogger(this.getClass());
	
	/**
	 * 经纬度单位(百万分之一)
	 */
	private static final double LAT_LNG_UNIT = 0.000001;
	/**
	 * 油耗单位(0.01升)
	 */
	private static final double OIL_UNIT = 0.01;
	/**
	 * 里程单位(0.1公里)
	 */
	private static final double DISTANCE_UNIT = 0.1;
	
	/**
	 * 刹车里程单位(0.01公里)
	 */
	private static final double BRAKE_DISTANCE_UNIT = 0.01;
	
	/**
	 * 瞬时油耗单位
	 */
	private static final double ENGINE_FULE_UNIT = 0.05;
	
	/**
	 * 总油耗单位
	 */
	private static final double TOTAL_FULE_UNIT = 0.5;
	
	/**
	 * 速度-转速 持续时间矩阵中转速维度(10档)
	 */
	private static final int ROTATING_DIMENSION = 10;
	
	/**
	 * 速度-转速 持续时间矩阵中速度维度(10档)
	 */
	private static final int SPEED_DIMENSION = 10;
	public CanDistance parseCanDistance(SmartMessage msg) {
		CanDistance canDistance = new CanDistance();
		byte[] data = msg.getData();
		Index index = new Index();
		canDistance.setType(2);
		canDistance.setImei(msg.getImei());
		canDistance.setDistanceMsgLength(parseCanDWord(data, index));
		
		canDistance.setDistanceNumber(parseCanDWord(data, index));

		canDistance.setStartTime(bcd2Date(data, index));

		double startLng = parseCanDWord(data, index);
		startLng = getFormatedVal(startLng, LAT_LNG_UNIT);
		canDistance.setStartLng(startLng);

		double startLat = parseCanDWord(data, index);
		startLat = getFormatedVal(startLat, LAT_LNG_UNIT);
		canDistance.setStartLat(startLat);

		canDistance.setStopTime(bcd2Date(data, index));
		
		double stopLnt = parseCanDWord(data, index);
		stopLnt = getFormatedVal(stopLnt, LAT_LNG_UNIT);
		canDistance.setStopLng(stopLnt);

		double stopLat = parseCanDWord(data, index);
		stopLat = getFormatedVal(stopLat, LAT_LNG_UNIT);
		canDistance.setStopLat(stopLat);

		canDistance.setLastDistanceStatus(parseCanByte2Int(data, index));

		canDistance.setDistanceMsgLength( parseCanDWord(data, index));

		double totalDistance = parseCanDWord(data, index) * 1000;
		totalDistance = getFormatedVal(totalDistance, DISTANCE_UNIT);
		canDistance.setTotalDistance(totalDistance);

		double ecuDistanceAtDistanceStart = parseCanDWord(data, index);
		ecuDistanceAtDistanceStart = getFormatedVal(ecuDistanceAtDistanceStart, DISTANCE_UNIT);
		canDistance.setEcuDistanceAtDistanceStart(ecuDistanceAtDistanceStart * 1000);

		canDistance.setTotalEngineRunningTime( parseCanDWord(data, index));

		canDistance.setOverRotatingTimes(parseCanWord(data, index));

		canDistance.setOverRotatingTime(parseCanDWord(data, index));

		canDistance.setMaxRotatingSpeed(parseCanWord(data, index));

		double brakeDistance = parseCanDWord(data, index) * 1000;
		brakeDistance = getFormatedVal(brakeDistance, BRAKE_DISTANCE_UNIT);
		canDistance.setBrakeDistance(brakeDistance);

		canDistance.setBrakeTimes(parseCanWord(data, index));

		canDistance.setBrakeTime(parseCanDWord(data, index));

		canDistance.setHardBrakeTimes(parseCanWord(data, index));

		canDistance.setOverSpeedingTimes(parseCanWord(data, index));

		canDistance.setOverSpeedingTime(parseCanDWord(data, index));

		canDistance.setMaxSpeed(parseCanWord(data, index));

		double totalOil = parseCanDWord(data, index);
		totalOil = getFormatedVal(totalOil, OIL_UNIT);
		canDistance.setTotalOil(totalOil);

		double idlingOil = parseCanDWord(data, index);
		idlingOil = getFormatedVal(idlingOil, OIL_UNIT);
		canDistance.setIdlingOil(idlingOil);

		double runningOil = parseCanDWord(data, index);
		runningOil = getFormatedVal(runningOil, OIL_UNIT);
		canDistance.setRunningOil(runningOil);

		canDistance.setIdlingTime(parseCanDWord(data, index));

		canDistance.setHotVehicleTime(parseCanWord(data, index));

		canDistance.setAbnormalIdlingTime(parseCanDWord(data, index));
		
		canDistance.setSpeedAndRotatingRelation(calcSpeedAndRotatingRelation(data, index));
		
		if(data.length > index.get()){
			canDistance.setPostedSpeedCount(parseCanWord(data, index));
		}
		return canDistance;
	}
	
	public List<CanDetailDongFeng> parseCanDetailForDongFeng(SmartMessage msg) {

		byte[] data = msg.getData();
		String imei = msg.getImei();
		Index index = new Index();
		int mesLength= parseCanWord(data, index);	
		if(mesLength!=data.length-3){
			log.error("消息体长度不匹配："+imei+"data: "+Hex.encodeHexString(data));
			return null;
		}
		Date uploadTime=new Date(System.currentTimeMillis());
		int count = parseCanByte2Int(data, index);
		List<CanDetailDongFeng> canDetailDFs = new ArrayList<CanDetailDongFeng>();
		CanDetailDongFeng canDetailDF = null;
		boolean firstRecordFlag=true;
		for (int i = 0; i < count; i++) {
				int dataId = parseCanByte2Int(data, index);		
				if(dataId==1){					
					if(firstRecordFlag){ 
						firstRecordFlag=false;						
					}else{
						canDetailDFs.add(canDetailDF);
					}
					canDetailDF = new CanDetailDongFeng();
					canDetailDF.setImei(imei);
					canDetailDF.setType(CanDetail.TYPE_SMART_CAN);
					canDetailDF.setUploadTime(uploadTime);
				}
				switch(dataId){
				    case 1:			
				    	Date date = bcd2Date(data, index);
						canDetailDF.setCreateTime(date);
						break;
					case 2:
						canDetailDF.setEngineSpeed((int)parseCanDWord(data,index));
						break;
					case 3:
						double engineFuel = getFormatedVal(parseCanDWord(data,index), ENGINE_FULE_UNIT);
						canDetailDF.setEngineFuel(engineFuel);
						break;
					case 4:
						double totalFuel = getFormatedVal(parseCanDWord(data,index), TOTAL_FULE_UNIT);
						canDetailDF.setEngineTotalFuel(totalFuel);
						break;
					case 5:
						canDetailDF.setBrake((int)parseCanDWord(data,index));
						break;
					case 6: 
						canDetailDF.setVehicleSpeedFefl(parseCanDWord(data,index));
						break;
					case 7:						
						canDetailDF.setVehicleSpeedFe6c(parseCanDWord(data,index));
					   break;	
					case 8: 
						double totalDistanceFec1 = getFormatedVal(parseCanDWord(data,index), DISTANCE_UNIT);
						canDetailDF.setTotalDistanceFec1(totalDistanceFec1);
						break;
					case 9:
						double totalDistanceFee0 = getFormatedVal(parseCanDWord(data,index), DISTANCE_UNIT);
						canDetailDF.setTotalDistanceFee0(totalDistanceFee0);
						break;
					case 10: 
						canDetailDF.setThrottleValve((int)parseCanDWord(data,index));
						break;
					case 11: 
						canDetailDF.setEngineCoolantTemperature((int)parseDWord2LongSign(data,index));
						break;
					case 12: 
						canDetailDF.setFuelPressure((int)parseCanDWord(data,index));
						break;
					case 13: 
						canDetailDF.setManifoldAbsolutePressure((int)parseCanDWord(data,index));
						break;
					case 14: 
						canDetailDF.setEngineInletTemperature((int)parseDWord2LongSign(data,index));						
						break;
					case 15: 
						canDetailDF.setAirFlow((int)parseCanDWord(data,index));
						break;
					case 16: 
						canDetailDF.setSolarTermDoorPositionSensor((int)parseCanDWord(data,index));
						break;
					case 17: 
						canDetailDF.setEngineRunningTime((int)parseCanDWord(data,index));
						break;
					case 18: 
						canDetailDF.setStrokeFuel((int)parseCanDWord(data,index));
						break;
					case 19:
						canDetailDF.setTorque((int)parseCanDWord(data,index));
				} 
               if(i==count-1){
            	   canDetailDFs.add(canDetailDF);
				}
		}
		return canDetailDFs;
	}
	
	
	public List<CanDetail> parseCanDetail(SmartMessage msg) {
		byte[] data = msg.getData();
		String imei = msg.getImei();
		Index index = new Index();
		int count = parseCanByte2Int(data, index);
		if (count == 0) {
			
		}
		List<CanDetail> canDetails = new ArrayList<CanDetail>(count);
		for (int i = 0; i < count; i++) {
			CanDetail canDetail = new CanDetail();
			canDetail.setImei(imei);
			canDetail.setType(CanDetail.TYPE_SMART_CAN);
			int idx = index.get();
			boolean isOK = true;
			if (data[idx] == 0 || data[idx + 1] == 0 || data[idx + 2] == 0) {
				// 跳过非法时间记录(年、月、日任意一位为0都为非法时间)
				isOK = false;;
			}
			canDetail.setCreateTime(bcd2Date(data, index));
			
			canDetail.setEngineSpeed(parseCanWord(data, index));
			
			double engineFuel = parseCanWord(data, index);
			engineFuel = getFormatedVal(engineFuel, ENGINE_FULE_UNIT);
			canDetail.setEngineFuel(engineFuel);
			
			double totalFuel = parseCanDWord(data, index);
			totalFuel = getFormatedVal(totalFuel, TOTAL_FULE_UNIT);
			canDetail.setEngineTotalFuel(totalFuel);
			
			canDetail.setBrake(parseCanByte2Int(data, index));
			
			canDetail.setVehicleSpeed(parseCanByte2Int(data, index));
			
			double totalDistance = parseCanDWord(data, index);
			totalDistance = getFormatedVal(totalDistance, DISTANCE_UNIT);
			canDetail.setTotalDistance(totalDistance);
			
			canDetail.setThrottleValve(parseCanByte2Int(data, index));
			
			canDetail.setEngineCoolantTemperature(parseByte2IntSign(data, index));
			
			canDetail.setFuelPressure(parseCanWord(data, index));
			
			canDetail.setManifoldAbsolutePressure(parseCanWord(data, index));
			
			canDetail.setEngineInletTemperature(parseByte2IntSign(data, index));
			
			canDetail.setAirFlow(parseCanWord(data, index));
			
			canDetail.setSolarTermDoorPositionSensor(parseCanByte2Int(data, index));
			
			canDetail.setEngineRunningTime(parseCanDWord(data, index));
			
			canDetail.setStrokeFuel(parseCanByte2Int(data, index));
			if (isOK) {
				canDetails.add(canDetail);
			}
		}
		return canDetails;
	}
	
	public String calcSpeedAndRotatingRelation(byte[] data, Index index){
		int idx = index.get();
		Index localIdx = new Index(idx);
		StringBuilder speedAndRotating = new StringBuilder();
		speedAndRotating.append("{");
		for (int i = 0; i < ROTATING_DIMENSION; i++) {
			speedAndRotating.append(calcSpeed(i)).append(":{");
			for (int j = 0; j < SPEED_DIMENSION; j++) {
				localIdx.setIndex(idx + (i + j * 10) * 4);
				long time = parseCanDWord(data, localIdx);
				speedAndRotating.append(calcRotatingSpeed(j)).append(":").append(time);
				if (j < SPEED_DIMENSION - 1) {
					speedAndRotating.append(",");
				} 
			}
			speedAndRotating.append("}");
			if (i < ROTATING_DIMENSION - 1) {
				speedAndRotating.append(",");
			}
		}
		speedAndRotating.append("}");
		index.setIndex(idx + ROTATING_DIMENSION * SPEED_DIMENSION * 4);
		return speedAndRotating.toString();
	}
	
	private int calcSpeed(int count){
		return 30 + 10 * count;
	}
	private int calcRotatingSpeed(int count){
		return 600 + 200 * count;
	}
}
